
#include "usart_drv.h"
#include "string.h"

#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"

#include "elog.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "usart_config.h"

#define LOG_TAG "UART"

#ifdef USE_USART_0
extern DMA_HandleTypeDef hdma_usart0_rx;
#endif

#ifdef USE_USART_1
extern DMA_HandleTypeDef hdma_usart1_rx;
#endif

#ifdef USE_USART_2
extern DMA_HandleTypeDef hdma_usart2_rx;
#endif

#ifdef USE_USART_3
extern DMA_HandleTypeDef hdma_usart3_rx;
#endif

#ifdef USE_USART_4
extern DMA_HandleTypeDef hdma_usart4_rx;
#endif

#ifdef USE_USART_5
extern DMA_HandleTypeDef hdma_usart5_rx;
#endif

#ifdef USE_USART_6
extern DMA_HandleTypeDef hdma_usart6_rx;
#endif

#ifdef USE_USART_7
extern DMA_HandleTypeDef hdma_usart7_rx;
#endif

#ifdef USE_USART_8
extern DMA_HandleTypeDef hdma_usart8_rx;
#endif

#ifdef USE_USART_9
extern DMA_HandleTypeDef hdma_usart9_rx;
#endif

#ifdef USE_USART_10
extern DMA_HandleTypeDef hdma_usart10_rx;
#endif

typedef struct
{
    UART_HandleTypeDef * huart;     //串口句柄
    DMA_HandleTypeDef* dma_t;       //dma
    uint16_t rx_len;                //接收数据长度
    uint16_t tx_len;                //发送数据长度
    uint8_t* rx_buffer;             //接收缓冲区
    uint8_t* tx_data;               //
    uint16_t rx_len_max;
    uint16_t tx_len_max;
    SemaphoreHandle_t mutex;        //互斥
    SemaphoreHandle_t rx_sem;       //接收信号量
}uart_t;


uart_t UART_TABLE[11] = 
{
    {
        #ifdef USE_USART_0
        .huart = &huart0,
        .dma_t = &hdma_usart0_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_1
        .huart = &huart1,
        .dma_t = &hdma_usart1_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_2
        .huart = &huart2,
        .dma_t = &hdma_usart2_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_3
        .huart = &huart3,
        .dma_t = &hdma_usart3_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_4
        .huart = &huart4,
        .dma_t = &hdma_usart4_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_5
        .huart = &huart5,
        .dma_t = &hdma_usart5_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_6
        .huart = &huart6,
        .dma_t = &hdma_usart6_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_7
        .huart = &huart7,
        .dma_t = &hdma_usart7_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_8
        .huart = &huart8,
        .dma_t = &hdma_usart8_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_9
        .huart = &huart9,
        .dma_t = &hdma_usart9_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
    {
        #ifdef USE_USART_10
        .huart = &huart10,
        .dma_t = &hdma_usart10_rx,
        #else
        .huart = NULL,
        .dma_t = NULL,
        #endif
    },
};
#define UART_TABLE_LEN (sizeof(UART_TABLE) / sizeof(uart_t))

/**
 * @brief 初始化对应串口号的MDA并开始接收
 * @param uart_dma 串口DMA结构体指针
 * @param huart 串口号
 * @param dma dma号
 * @return 
 */
uint8_t uart_dma_init(uint8_t uart_index, uint16_t rx_buf_size, uint16_t tx_buf_size)
{
    uart_t *uart = &UART_TABLE[uart_index];
    if (uart->huart == NULL ||  uart->dma_t == NULL)
    {
        log_e("plase check your uart config");
        return 1;

    } 
    uart->rx_len = 0;
    uart->rx_len_max = rx_buf_size;
    uart->tx_len_max = tx_buf_size;
    uart->mutex = xSemaphoreCreateMutex();
    uart->rx_sem = xSemaphoreCreateBinary();

    uart->rx_buffer = (uint8_t *)pvPortMalloc(rx_buf_size);
    if (uart->rx_buffer == NULL)
    {
        log_e("uart_dma_init malloc error");
        vPortFree(uart->rx_buffer);
    }
    uart->tx_data = (uint8_t *)pvPortMalloc(tx_buf_size);
    if (uart->tx_data == NULL)
    {
        log_e("uart_dma_init malloc error");
        vPortFree(uart->tx_data);
    }
    
    /*开启空闲中断并开启DMA接收*/
    __HAL_UART_ENABLE_IT(uart->huart, UART_IT_IDLE);
    HAL_UART_Receive_DMA(uart->huart, uart->rx_buffer, rx_buf_size);
    return 0;
}



/**
 * @brief 串口空闲中断
 *        直接在串口IRQ中调用
 * @param uart_dma 串口DMA结构体指针
 */
void uart_idle_callback(uint8_t uart_index)
{
    uart_t *uart = &UART_TABLE[uart_index];
    uint16_t rx_max = uart->rx_len_max;
    if(__HAL_UART_GET_FLAG(uart->huart, UART_FLAG_IDLE) != RESET)
    {
        __HAL_UART_CLEAR_IDLEFLAG(uart->huart);
        HAL_UART_DMAStop(uart->huart);
        uart->rx_len = rx_max - __HAL_DMA_GET_COUNTER(uart->dma_t);
        memset(uart->rx_buffer + uart->rx_len, 0, rx_max - uart->rx_len);
        HAL_UART_Receive_DMA(uart->huart, uart->rx_buffer, rx_max);

        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xSemaphoreGiveFromISR(uart->rx_sem, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

/**
 * @brief 串口发送 应用层调用
 * @param uart 串口句柄
 * @param data 发送数据
 * @param len 数据长度
 * @param block_time 阻塞时间
 * @return 1-失败 0成功
 */
uint8_t uart_transmit(uint8_t uart_index, uint8_t* data, uint16_t len)
{
    uart_t *uart = &UART_TABLE[uart_index];
    if(uart->mutex != NULL)
    {
        xSemaphoreTake(uart->mutex, 200);
        HAL_UART_Transmit(uart->huart, data, len, 100);
        xSemaphoreGive(uart->mutex);
    }
    else
    {
        HAL_UART_Transmit(uart->huart, data, len, 200);
    }
    return 0;
}



/**
 * @brief 串口接收
 * @param uart uart_index 串口索引
 * @param data 数据缓冲指针
 * @param data_size 数据缓冲区大小
 * @param time_out 超时时间
 * @return -1 参数错误 0：超时 other：接收到数据长度
 */
int uart_receive(uint8_t uart_index, uint8_t* data, uint32_t data_size, uint32_t time_out)
{
    if (uart_index >= UART_TABLE_LEN){
        return -1;
    }
    uart_t *uart = &UART_TABLE[uart_index];
    if (xSemaphoreTake(uart->rx_sem, time_out) != pdTRUE){
        return 0;
    }    

    if (uart->rx_len > data_size) {
        return -2;
    }

    memcpy(data, uart->rx_buffer, uart->rx_len);
    return uart->rx_len;
}

/**
 * @brief 串口接收 中断中调用
 * @param uart uart_index 串口索引
 * @param data 数据缓冲指针
 * @param data_size 数据缓冲区大小
 * @return -1 参数错误 0：超时 other：接收到数据长度
 */
int uart_receive_from_isr(uint8_t uart_index, uint8_t* data, uint32_t data_size)
{
    if (uart_index >= UART_TABLE_LEN){
        return -1;
    }
    uart_t *uart = &UART_TABLE[uart_index];
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    BaseType_t xResult = pdTRUE;
    xResult = xSemaphoreTakeFromISR(uart->rx_sem, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

    if (xResult != pdTRUE) {
        return 0;
    }

    if (uart->rx_len > data_size) {
        return -2;
    }

    memcpy(data, uart->rx_buffer, uart->rx_len);
    return uart->rx_len;
}


/**
 * @brief 串口打印数据(直接输出)
 * @param uart 串口句柄
 * @param format 
 * @return 
 */
int uart_print_fast(uint8_t uart_index, const char* format, ...)
{
    uint32_t print_length = 0;
    uart_t *uart = &UART_TABLE[uart_index];
    memset(uart->tx_data, 0, print_length);
    va_list args;
    va_start(args, format);
    print_length = vsnprintf(uart->tx_data, uart->tx_len_max, format, args);
    va_end(args);
    if (print_length > uart->tx_len_max) {
        log_e("uart_print_fast: print_length > uart->tx_len_max");
        return -1;
    }
    return HAL_UART_Transmit(uart->huart, uart->tx_data, print_length, 10);
}


/**
 * @brief 串口打印数据追加换行(直接输出)
 * @param uart 串口句柄
 * @param format 
 * @return 
 */
int uart_println_fast(uint8_t uart_index, const char* format, ...)
{
    uint32_t print_length = 0;
    uart_t *uart = &UART_TABLE[uart_index];
    memset(uart->tx_data, 0, print_length);
    va_list args;
    va_start(args, format);
    print_length = vsnprintf(uart->tx_data, uart->tx_len_max, format, args);
    print_length += sprintf(uart->tx_data + print_length, "\r\n");
    va_end(args);
    // return HAL_UART_Transmit(uart->huart, uart->tx_data, print_length, 10);
    for (uint32_t i = 0; i < print_length; i++)
    {
        // 等待发送数据寄存器空
        while (!(uart->huart->Instance->SR & UART_FLAG_TXE));
        
        // 写入数据到数据寄存器
        uart->huart->Instance->DR = uart->tx_data[i];
    }
    return 0;
}

/**
 * @brief 调试打印函数 直接调用调试串口
 * @param format 
 * @param  
 * @note 此函数会将日志写入缓存 
 */
int uart_log_print(const char* format, ...)
{
    uart_t *uart = &UART_TABLE[DEBUG_UART_INDEX];
    uint32_t log_size = 0;
    memset(uart->tx_data, 0, uart->tx_len_max);
    va_list args;
    va_start(args, format);
    log_size = vsnprintf(uart->tx_data, uart->tx_len_max, format, args);
    va_end(args);
    elog_port_write_ringbuffer(uart->tx_data, log_size);

    for (uint32_t i = 0; i < log_size; i++)
    {
        // 等待发送数据寄存器空
        while (!(uart->huart->Instance->SR & UART_FLAG_TXE));
        
        // 写入数据到数据寄存器
        uart->huart->Instance->DR = uart->tx_data[i];
    }
}

//printf重定向
int fputc(int ch,FILE *p)
{
    uart_t *uart = &UART_TABLE[DEBUG_UART_INDEX];
	HAL_UART_Transmit(uart->huart,(uint8_t *)&ch,1,100);
	return ch;
}